package gnss

import (
	"dgo/goutils/utils"
	"math"
	"time"
)

type EDCodeChecker struct {
	LogTypeStr    string
	rtcmRawBuf    *Rtcm3RawBuf
	OnCompareDone func(obs *RtcmRawMsmObs, rawBuf []byte)
	OnGetTimeFunc func() time.Time
	OnErrFunc     func(errtype int, err error)
	OnCompareFunc func(sn int, rawBuf []byte, obs_m, obs_s *GnssObsSign) bool
}

func (this *EDCodeChecker) InnerGetTime() time.Time {
	if this.OnGetTimeFunc != nil {
		return this.OnGetTimeFunc()
	} else {
		return time.Now()
	}
}

func (this *EDCodeChecker) InputBuf(buf []byte) {
	if this.rtcmRawBuf == nil {
		this.rtcmRawBuf = NewRtcm32RawBuf("")
		this.rtcmRawBuf.OnErr = func(errcode int, err error) bool {
			if this.OnErrFunc != nil {
				this.OnErrFunc(0, err)
			} else {
				utils.Log.WarnTypef(this.LogTypeStr, "RTCM解码(%d)异常:%s", errcode, err.Error())
			}
			return true
		}
	}

	rtcmRawBuf := this.rtcmRawBuf

	var bb utils.BytesBuilder
	for i := 0; i < len(buf); i++ {
		r := rtcmRawBuf.InputBuf(buf[i])
		if r == 1 {
			rtcmBuf := rtcmRawBuf.GetRawBuf()
			msgid := uint16(GetRtcmMsgId(rtcmBuf, 24))
			if RtcmIsMsm4(msgid) {
				msm4 := NewRtcmRawMsm4()
				e1 := msm4.DecodeMsm(rtcmBuf)
				if e1 != nil {
					if this.OnErrFunc != nil {
						this.OnErrFunc(1, e1)
					} else {
						utils.Log.WarnTypef(this.LogTypeStr, "MSM解码异常:%s", e1.Error())
					}
				} else {
					obs := NewRtcmRawMsmObs()
					obs.CopyFromMsm(msm4)

					msmEn := NewRtcmRawMsm4()
					msmEn.CopyFromObsWhole(obs, msm4.Header.EpochEndFlag, nil)
					bb.Reset()
					msmEn.EncodeMsm(&bb, 0)

					msm4_1 := NewRtcmRawMsm4()
					e2 := msm4_1.DecodeMsm(bb.Bytes())
					if e2 != nil {
						if this.OnErrFunc != nil {
							this.OnErrFunc(2, e1)
						} else {
							utils.Log.WarnTypef(this.LogTypeStr, "编码后解码出现异常:%s, rawBuf:%s", e1.Error(), utils.BufToHexStr(rtcmBuf, 0, ""))
						}
					} else {
						obs_1 := NewRtcmRawMsmObs()
						obs_1.CopyFromMsm(msm4_1)

						if this.OnCompareFunc != nil {
							sn := 0
							obs.Compare(obs_1, func(obs_m, obs_s *GnssObsSign) bool {
								sn0 := sn
								sn++
								return this.OnCompareFunc(sn0, rtcmBuf, obs_m, obs_s)
							})
						} else {
							output_n := 0
							t0 := obs.Header.GetGPSTime(this.InnerGetTime())
							t1 := obs_1.Header.GetGPSTime(this.InnerGetTime())
							if !t0.Equal(t1) {
								utils.Log.WarnTypef(this.LogTypeStr, "[%s] decode time err:[%s]-[%s]", msm4.Header.MsgID, utils.DateTimeString3(t0), utils.DateTimeString3(t1))
								output_n++
							}
							obs.Compare(obs_1, func(obs_m, obs_s *GnssObsSign) bool {
								if math.Abs(obs_m.PsRng-obs_s.PsRng) > 0.001 {
									utils.Log.WarnTypef(this.LogTypeStr, "%s %s psrng: %.4f != %.4f\n", obs_m.PrnId(), obs_m.SigId, obs_m.PsRng, obs_s.PsRng)
									output_n++
								}

								if math.Abs(obs_m.PhRng-obs_s.PhRng) > 0.001 {
									utils.Log.WarnTypef(this.LogTypeStr, "%s %s phrng: %.4f != %.4f\n", obs_m.PrnId(), obs_m.SigId, obs_m.PsRng, obs_s.PsRng)
									output_n++
								}
								return true
							})

							if output_n > 0 {
								utils.Log.WarnTypef(this.LogTypeStr, "[%s]T:%s, RAW:%s", msm4.Header.MsgID, msm4.GetHeader().GetGPSTime(this.InnerGetTime()), utils.BufToHexStr(rtcmBuf, 0, ""))
							}
						}
					}

					if this.OnCompareDone != nil {
						this.OnCompareDone(obs, rtcmBuf)
					}

				}
			}
		}
	}

}
